# -*- coding: UTF-8 -*-

"""
任务的构成
"""

import DCLib.Unit
import os
import DCLib.Config
import json
import shutil


def init():
    task = DCLib.Unit.UnifyTask()
    return task


class Observe:
    @classmethod
    def set_strategy(cls, target_task: DCLib.Unit.UnifyTask, observe_task: DCLib.Unit.UnifyTask):
        if observe_task is not None:
            # 将observe_task里面的执行图取出来，放在一开始的位置
            # 将节点拷贝出来
            for ob_task_node in observe_task.all_real_view_node:
                target_task.all_real_view_node.append(ob_task_node)
            # 如果一开始是空的
            if len(target_task.all_real_view_node) == len(observe_task.all_real_view_node):
                target_task.entrance = observe_task.entrance
                target_task.exit = observe_task.exit
            else:
                # 接在尾部
                observe_task.entrance.input_data = target_task.exit
                target_task.exit.task_to_arr.append(observe_task.entrance)
                target_task.exit = observe_task.exit
        else:
            print("no observe")


class OrientDecide:
    @classmethod
    def register_seq_op(cls, target_task: DCLib.Unit.UnifyTask, library_file_name: str, function_name: str):
        # 查看文件是不是存在
        python_cache_file_name = DCLib.Config.TMP_DIR + "python_script_cache/task_ppy" + target_task.task_id + ".ppy"
        # 加入记录
        old_size = len(target_task.seq_fun_set)
        target_task.seq_fun_set.add((library_file_name, function_name))
        if old_size == len(target_task.seq_fun_set):
            print("this function has been register")
            return

        if not os.path.exists(python_cache_file_name):
            # 创建写
            open(python_cache_file_name, "w").write(
                "\n" + DCLib.Tool.read_file_and_get_function(library_file_name, function_name) + "\n")
        else:
            # 追加写
            open(python_cache_file_name, "a").write(
                "\n" + DCLib.Tool.read_file_and_get_function(library_file_name, function_name) + "\n")

    @classmethod
    def register_para_op(cls, target_task: DCLib.Unit.UnifyTask, library_file_name: str, function_name: str):
        python_cache_file_name = DCLib.Config.TMP_DIR + "python_script_cache/task_ppy" + target_task.task_id + ".ppy"

        old_size = len(target_task.para_fun_set)
        target_task.para_fun_set.add((library_file_name, function_name))
        if old_size == len(target_task.para_fun_set):
            print("this function has been register")
            return

        if not os.path.exists(python_cache_file_name):
            # 创建写
            open(python_cache_file_name, "w").write(
                "\n" + DCLib.Tool.read_file_and_get_function(library_file_name, function_name) + "\n")
        else:
            # 追加写
            open(python_cache_file_name, "a").write(
                "\n" + DCLib.Tool.read_file_and_get_function(library_file_name, function_name) + "\n")


class Act:
    @classmethod
    def set_filter(cls, target_task: DCLib.Unit.UnifyTask, filter_task: DCLib.Unit.UnifyTask):
        # 设置过滤器，里面的逻辑和设置observe差不多
        if filter_task is not None:
            # 将observe_task里面的执行图取出来，放在一开始的位置
            # 将节点拷贝出来
            for ob_task_node in filter_task.all_real_view_node:
                target_task.all_real_view_node.append(ob_task_node)
            # 如果一开始是空的
            if len(target_task.all_real_view_node) == len(filter_task.all_real_view_node):
                target_task.entrance = filter_task.entrance
                target_task.exit = filter_task.exit
            else:
                # 接在尾部
                filter_task.entrance.input_data = target_task.exit
                target_task.exit.task_to_arr.append(filter_task.entrance)
                target_task.exit = filter_task.exit
        else:
            print("no observe")

    @classmethod
    def build(cls, target_task: DCLib.Unit.UnifyTask, para_func_name: str, share={}):
        # 要执行的ppy文件
        ppy_cache_file_name = DCLib.Config.TMP_DIR + "python_script_cache/task_ppy" + target_task.task_id + ".ppy"
        # 预处理json的位置
        pre_ana_report = DCLib.Config.TMP_DIR + "python_script_cache/pre_ana" + target_task.task_id + ".json"
        # 生成命令
        # 参数部分
        param_part = ""
        param_part = param_part + " -i " + ppy_cache_file_name

        for seq_fun_name in target_task.seq_fun_set:
            param_part = param_part + " -s " + seq_fun_name[1]

        param_part = param_part + " -p " + para_func_name
        param_part = param_part + " -r " + pre_ana_report

        # 执行命令
        os.system(DCLib.Config.TRANSLATER_LOCATION + param_part)

        # 查看对应文件是不是存在
        if not os.path.exists(pre_ana_report):
            print("some error happened in translator")
            exit(-1)

        # 解析文件内容
        report_map = json.loads(open(pre_ana_report).read())



        # 产生一个真实视图的task
        if report_map["hadoop_MR"]:
            # 当做本地进行编译
            param_part = ""
            param_part = param_part + " -i " + ppy_cache_file_name

            for seq_fun_name in target_task.seq_fun_set:
                param_part = param_part + " -s " + seq_fun_name[1]

            param_part = param_part + " -p " + para_func_name
            param_part = param_part + " -t " + "hadoop_MR"
            os.system(DCLib.Config.TRANSLATER_LOCATION + param_part)
            mapper_py_file_name = DCLib.Config.TMP_DIR + "python_script_cache/mapper_task_py" + target_task.task_id + ".py"
            reducer_py_file_name = DCLib.Config.TMP_DIR + "python_script_cache/reducer_task_py" + target_task.task_id + ".py"

            # 转移mapper文件
            if os.path.exists("./" + para_func_name + "_mapper.py"):
                shutil.move("./" + para_func_name + "_mapper.py", mapper_py_file_name)
            else:
                print("some error happened in MR translator building")
                exit(-1)

            if report_map["reduce_op"] == True:
                # 转移reducer文件
                if os.path.exists("./" + para_func_name + "_reducer.py"):
                    shutil.move("./" + para_func_name + "_reducer.py", reducer_py_file_name)
                else:
                    print("some error happened in MR translator building")
                    exit(-1)
            else:
                reducer_py_file_name = ""

            # 处理share
            share_str = json.dumps(json.dumps(share))
            add_code = "import json\nshare = json.loads(" + share_str + ")\n"

            with open(mapper_py_file_name, "r+") as f:
                old = f.read()
                f.seek(0)
                f.write(add_code)
                f.write(old)

            if report_map["reduce_op"] == True:
                with open(reducer_py_file_name, "r+") as f:
                    old = f.read()
                    f.seek(0)
                    f.write(add_code)
                    f.write(old)

            # 构建MR任务
            if DCLib.Config.LOCAL_MR:
                new_task = DCLib.RealView.LocalMapReduceNode(mapper_py_file_name, reducer_py_file_name)
                target_task.all_real_view_node.append(new_task)
                # 本地任务，生成一个本地数据节点
                new_data = DCLib.RealView.LocalDataNode("")
                target_task.all_real_view_node.append(new_data)
                # 连在一起
                new_task.output_data = new_data
                new_data.task_from = new_task
                # 和之前以后的任务连接
                if len(target_task.all_real_view_node) == 2:
                    target_task.entrance = new_task
                    target_task.exit = new_data
                else:
                    # task中已经有了，连在后面
                    new_task.input_data = target_task.exit
                    target_task.exit.task_to_arr.append(new_task)
                    target_task.exit = new_data

            else:
                new_task = DCLib.RealView.HadoopMrTaskNode(mapper_py_file_name, reducer_py_file_name)
                target_task.all_real_view_node.append(new_task)
                # 生成一个HDFS的Data节点
                new_data = DCLib.RealView.HDFSDataNode(new_task.hdfs_ip, new_task.hdfs_port)
                target_task.all_real_view_node.append(new_data)
                # 连在一起
                new_task.output_data = new_data
                new_data.task_from = new_task
                # 和之前的任务链接
                if len(target_task.all_real_view_node) == 2:
                    target_task.entrance = new_task
                    target_task.exit = new_data
                else:
                    # task中已经有了，连在后面
                    new_task.input_data = target_task.exit
                    target_task.exit.task_to_arr.append(new_task)
                    target_task.exit = new_data

        else:
            # 当做本地进行编译
            param_part = ""
            param_part = param_part + " -i " + ppy_cache_file_name

            for seq_fun_name in target_task.seq_fun_set:
                param_part = param_part + " -s " + seq_fun_name[1]

            param_part = param_part + " -p " + para_func_name
            param_part = param_part + " -t " + "local"
            os.system(DCLib.Config.TRANSLATER_LOCATION + param_part)

            local_py_file_name = DCLib.Config.TMP_DIR + "python_script_cache/local_task_py" + target_task.task_id + ".py"
            # 转移生成的文件
            if os.path.exists("./" + para_func_name + "_local_seq.py"):
                shutil.move("./" + para_func_name + "_local_seq.py", local_py_file_name)
            else:
                print("some error happened in translator building")
                exit(-1)

            # 将share序列化成字符串，然后在文件中解析一次
            share_str = json.dumps(json.dumps(share))
            add_code = "import json\nshare = json.loads(" + share_str + ")\n"
            # 生成一个新的任务，放在当前的任务链的尾部，并且附带一个datanode
            # 将share的初始化放到文件的头几行
            with open(local_py_file_name, "r+") as f:

                old = f.read()
                f.seek(0)
                f.write(add_code)
                f.write(old)

            new_task = DCLib.RealView.LocalTaskNode(local_py_file_name)
            target_task.all_real_view_node.append(new_task)
            # 生成一个数据节点
            new_data = DCLib.RealView.LocalDataNode("")
            target_task.all_real_view_node.append(new_data)
            # 连在一起
            new_task.output_data = new_data
            new_data.task_from = new_task

            if len(target_task.all_real_view_node) == 2:
                target_task.entrance = new_task
                target_task.exit = new_data
            else:
                # task中已经有了，连在后面
                new_task.input_data = target_task.exit
                target_task.exit.task_to_arr.append(new_task)
                target_task.exit = new_data
